home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / CPP / WFC010.ZIP / SRC / REGISTRY.CPP < prev    next >
C/C++ Source or Header  |  1995-12-07  |  31KB  |  1,216 lines

  1. #include <wfc.h>
  2. #pragma hdrstop
  3.  
  4. /*
  5. ** Author: Samuel R. Blackburn
  6. ** CI$: 76300,326
  7. ** Internet: sammy@sed.csc.com
  8. **
  9. ** You can use it any way you like as long as you don't try to sell it.
  10. **
  11. ** Any attempt to sell WFC in source code form must have the permission
  12. ** of the original author. You can produce commercial executables with
  13. ** WFC but you can't sell WFC.
  14. **
  15. ** Copyright, 1995, Samuel R. Blackburn
  16. **
  17. ** $Workfile: $
  18. ** $Revision: $
  19. ** $Modtime: $
  20. */
  21.  
  22. #if defined( _DEBUG )
  23. #undef THIS_FILE
  24. static char BASED_CODE THIS_FILE[] = __FILE__;
  25. #endif
  26.  
  27. IMPLEMENT_DYNAMIC( CRegistry, CObject );
  28.  
  29. #if defined( _DEBUG )
  30. #define new DEBUG_NEW
  31. #endif
  32.  
  33. const HKEY CRegistry::keyLocalMachine = HKEY_LOCAL_MACHINE;
  34. const HKEY CRegistry::keyClassesRoot  = HKEY_CLASSES_ROOT;
  35. const HKEY CRegistry::keyUsers        = HKEY_USERS;
  36. const HKEY CRegistry::keyCurrentUser  = HKEY_CURRENT_USER;
  37.  
  38. CRegistry::CRegistry()
  39. {
  40.    m_Initialize();
  41. }
  42.  
  43. CRegistry::~CRegistry()
  44. {
  45.    if ( m_RegistryHandle != (HKEY) NULL )
  46.    {
  47.       Close();
  48.    }
  49.  
  50.    m_Initialize();
  51. }
  52.  
  53. void CRegistry::m_Initialize( void )
  54. {
  55.    ASSERT_VALID( this );
  56.  
  57.    /*
  58.    ** Make sure everything is zeroed out
  59.    */
  60.  
  61.    m_ClassName.Empty();
  62.    m_ComputerName.Empty();
  63.    m_KeyName.Empty();
  64.    m_RegistryName.Empty();
  65.  
  66.    m_KeyHandle                    = (HKEY) NULL;
  67.    m_ErrorCode                    = 0L;
  68.    m_NumberOfSubkeys              = 0;
  69.    m_LongestSubkeyNameLength      = 0;
  70.    m_LongestClassNameLength       = 0;
  71.    m_NumberOfValues               = 0;
  72.    m_LongestValueNameLength       = 0;
  73.    m_LongestValueDataLength       = 0;
  74.    m_SecurityDescriptorLength     = 0;
  75.    m_LastWriteTime.dwLowDateTime  = 0;
  76.    m_LastWriteTime.dwHighDateTime = 0;
  77. }
  78.  
  79. BOOL CRegistry::Close( void )
  80. {
  81.    ASSERT_VALID( this );
  82.  
  83.    if ( m_RegistryHandle == (HKEY) NULL )
  84.    {
  85.       return( TRUE );
  86.    }
  87.  
  88.    m_ErrorCode = ::RegCloseKey( m_RegistryHandle );
  89.  
  90.    if ( m_ErrorCode == ERROR_SUCCESS )
  91.    {
  92.       m_RegistryHandle = (HKEY) NULL;
  93.       m_Initialize();
  94.  
  95.       return( TRUE );
  96.    }
  97.    else
  98.    {
  99.       return( FALSE );
  100.    }
  101. }
  102.  
  103. BOOL CRegistry::Connect( HKEY key_to_open, LPCTSTR name_of_computer )
  104. {
  105.    ASSERT_VALID( this );
  106.  
  107.    /*
  108.    ** name_of_computer can be NULL
  109.    */
  110.  
  111.    if ( key_to_open == keyClassesRoot || key_to_open == keyCurrentUser )
  112.    {
  113.       if ( name_of_computer == NULL )
  114.       {
  115.          /*
  116.          ** NT won't allow you to connect to these hives via RegConnectRegistry so we'll just skip that step
  117.          */
  118.  
  119.          m_RegistryHandle = key_to_open;
  120.          m_ErrorCode      = ERROR_SUCCESS;
  121.       }
  122.       else
  123.       {
  124.          m_ErrorCode = ERROR_INVALID_HANDLE;
  125.       }
  126.    }
  127.    else
  128.    {
  129.       m_ErrorCode = ::RegConnectRegistry( (char *) name_of_computer, key_to_open, &m_RegistryHandle );
  130.    }
  131.  
  132.    if ( m_ErrorCode == ERROR_SUCCESS )
  133.    {
  134.       if ( name_of_computer == NULL )
  135.       {
  136.          TCHAR computer_name[ MAX_PATH ] = "";
  137.          DWORD size = MAX_PATH;
  138.  
  139.          if ( ::GetComputerName( computer_name, &size ) == TRUE )
  140.          {
  141.             m_ComputerName = computer_name;
  142.          }
  143.          else
  144.          {
  145.             m_ComputerName.Empty();
  146.          }
  147.       }
  148.       else
  149.       {
  150.          m_ComputerName = name_of_computer;
  151.       }
  152.  
  153.       /*
  154.       ** It would be nice to use a switch statement here but I get a "not integral" error!
  155.       */
  156.  
  157.       if ( key_to_open == HKEY_LOCAL_MACHINE )
  158.       {
  159.          m_RegistryName = "HKEY_LOCAL_MACHINE";
  160.       }
  161.       else if ( key_to_open == HKEY_CLASSES_ROOT )
  162.       {
  163.          m_RegistryName = "HKEY_CLASSES_ROOT";
  164.       }
  165.       else if ( key_to_open == HKEY_USERS )
  166.       {
  167.          m_RegistryName = "HKEY_USERS";
  168.       }
  169.       else if ( key_to_open == HKEY_CURRENT_USER )
  170.       {
  171.          m_RegistryName = "HKEY_CURRENT_USER";
  172.       }
  173.       else
  174.       {
  175.          m_RegistryName = "Unknown";
  176.       }
  177.  
  178.       return( TRUE );
  179.    }
  180.    else
  181.    {
  182.       return( FALSE );
  183.    }
  184. }
  185.  
  186. BOOL CRegistry::Create( LPCTSTR               name_of_subkey, 
  187.                         LPCTSTR               name_of_class,
  188.                         CreateOptions         options, 
  189.                         CreatePermissions     permissions, 
  190.                         LPSECURITY_ATTRIBUTES security_attributes_p,
  191.                         CreationDisposition * disposition_p )
  192. {
  193.    ASSERT_VALID( this );
  194.    ASSERT( name_of_subkey != NULL );
  195.  
  196.    if ( name_of_subkey == NULL )
  197.    {
  198.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  199.       return( FALSE );
  200.    }
  201.  
  202.    DWORD disposition = 0;
  203.  
  204.    if ( name_of_class == NULL )
  205.    {
  206.       name_of_class = "";
  207.    }
  208.  
  209.    m_ErrorCode = ::RegCreateKeyEx( m_RegistryHandle,
  210.                                    name_of_subkey,
  211.                            (DWORD) 0,
  212.                           (char *) name_of_class,
  213.                                    options,
  214.                                    permissions,
  215.                                    security_attributes_p,
  216.                                   &m_KeyHandle,
  217.                                   &disposition );
  218.  
  219.    if ( m_ErrorCode == ERROR_SUCCESS )
  220.    {
  221.       if ( disposition_p != NULL )
  222.       {
  223.          *disposition_p = (CreationDisposition) disposition;
  224.       }
  225.  
  226.       m_KeyName = name_of_subkey;
  227.  
  228.       return( TRUE );
  229.    }
  230.    else
  231.    {
  232.       return( FALSE );
  233.    }
  234. }
  235.  
  236. BOOL CRegistry::DeleteKey( LPCTSTR name_of_key_to_delete )
  237. {
  238.    ASSERT_VALID( this );
  239.    ASSERT( name_of_key_to_delete != NULL );
  240.  
  241.    if ( name_of_key_to_delete == NULL )
  242.    {
  243.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  244.       return( FALSE );
  245.    }
  246.  
  247.    /*
  248.    ** You can't delete a key given a full path. What you have to do is back up one level and then do a delete
  249.    */
  250.  
  251.    CString full_key_name = name_of_key_to_delete;
  252.  
  253.    if ( full_key_name.Find( '\\' ) == (-1) )
  254.    {
  255.       /*
  256.       ** User had not given us a full path so assume the name of the key he passed us
  257.       ** is a key off of the current key
  258.       */
  259.  
  260.       m_ErrorCode = ::RegDeleteKey( m_KeyHandle, name_of_key_to_delete );
  261.    }
  262.    else
  263.    {
  264.       int last_back_slash_location = full_key_name.GetLength() - 1;
  265.  
  266.       /*
  267.       ** We know this loop will succeed because a back slash was found in the above if statement
  268.       */
  269.  
  270.       while( full_key_name[ last_back_slash_location ] != '\\' )
  271.       {
  272.          last_back_slash_location--;
  273.       }
  274.  
  275.       CString currently_opened_key_name = m_KeyName;
  276.  
  277.       CString parent_key_name = full_key_name.Left( last_back_slash_location );
  278.       CString child_key_name  = full_key_name.Right( ( full_key_name.GetLength() - last_back_slash_location ) - 1 );
  279.  
  280.       /*
  281.       ** Now we open the parent key and delete the child
  282.       */
  283.  
  284.       if ( Open( parent_key_name ) == TRUE )
  285.       {
  286.          m_ErrorCode = ::RegDeleteKey( m_KeyHandle, child_key_name );
  287.       }
  288.       else
  289.       {
  290.          m_KeyName = currently_opened_key_name;
  291.          return( FALSE );
  292.       }
  293.    }
  294.  
  295.    if ( m_ErrorCode == ERROR_SUCCESS )
  296.    {
  297.       return( TRUE );
  298.    }
  299.    else
  300.    {
  301.       return( FALSE );
  302.    }
  303. }                  
  304.  
  305. BOOL CRegistry::DeleteValue( LPCTSTR name_of_value_to_delete )
  306. {
  307.    ASSERT_VALID( this );
  308.  
  309.    /*
  310.    ** name_of_value_to_delete can be NULL
  311.    */
  312.  
  313.    m_ErrorCode = ::RegDeleteValue( m_KeyHandle, (LPTSTR) name_of_value_to_delete );
  314.  
  315.    if ( m_ErrorCode == ERROR_SUCCESS )
  316.    {
  317.       return( TRUE );
  318.    }
  319.    else
  320.    {
  321.       return( FALSE );
  322.    }
  323. }
  324.  
  325. #if defined( _DEBUG )
  326.  
  327. void CRegistry::Dump( CDumpContext& dump_context ) const
  328. {
  329.    CObject::Dump( dump_context );
  330.  
  331.    dump_context << "m_KeyHandle = "                << m_KeyHandle                << "\n";
  332.    dump_context << "m_RegistryHandle = "           << m_RegistryHandle           << "\n";
  333.    dump_context << "m_ClassName = \""              << m_ClassName                << "\"\n";
  334.    dump_context << "m_ComputerName = \""           << m_ComputerName             << "\"\n";
  335.    dump_context << "m_KeyName = \""                << m_KeyName                  << "\"\n";
  336.    dump_context << "m_RegistryName = \""           << m_RegistryName             << "\"\n";
  337.    dump_context << "m_NumberOfSubkeys = "          << m_NumberOfSubkeys          << "\n";
  338.    dump_context << "m_NumberOfValues = "           << m_NumberOfValues           << "\n";
  339.    dump_context << "m_LongestSubkeyNameLength = "  << m_LongestSubkeyNameLength  << "\n";
  340.    dump_context << "m_LongestClassNameLength = "   << m_LongestClassNameLength   << "\n";
  341.    dump_context << "m_LongestValueNameLength = "   << m_LongestValueNameLength   << "\n";
  342.    dump_context << "m_LongestValueDataLength = "   << m_LongestValueDataLength   << "\n";
  343.    dump_context << "m_SecurityDescriptorLength = " << m_SecurityDescriptorLength << "\n";
  344.    dump_context << "m_LastWriteTime = "            << m_LastWriteTime            << "\n";
  345. }
  346.  
  347. #endif // _DEBUG
  348.  
  349. BOOL CRegistry::EnumerateKeys( const DWORD subkey_index, CString& subkey_name, CString& class_name )
  350. {
  351.    ASSERT_VALID( this );
  352.  
  353.    TCHAR subkey_name_string[ 2048 ];
  354.    TCHAR class_name_string[ 2048 ];
  355.  
  356.    DWORD size_of_subkey_name_string = sizeof( subkey_name_string ) - 1;
  357.    DWORD size_of_class_name_string  = sizeof( class_name_string  ) - 1;
  358.  
  359.    ::ZeroMemory( subkey_name_string, sizeof( subkey_name_string ) );
  360.    ::ZeroMemory( class_name_string,  sizeof( class_name_string  ) );
  361.  
  362.    m_ErrorCode = ::RegEnumKeyEx( m_KeyHandle, 
  363.                                  subkey_index, 
  364.                                  subkey_name_string, 
  365.                                 &size_of_subkey_name_string,
  366.                                  NULL,
  367.                                  class_name_string,
  368.                                 &size_of_class_name_string,
  369.                                 &m_LastWriteTime );
  370.  
  371.    if ( m_ErrorCode == ERROR_SUCCESS )
  372.    {
  373.       subkey_name = subkey_name_string;
  374.       class_name  = class_name_string;
  375.  
  376.       return( TRUE );
  377.    }
  378.    else
  379.    {
  380.       return( FALSE );
  381.    }
  382. }
  383.  
  384. BOOL CRegistry::EnumerateValues( const DWORD    value_index, 
  385.                                  CString&       name_of_value, 
  386.                                  KeyValueTypes& type_code,
  387.                                  LPBYTE         data_buffer,
  388.                                  DWORD&         size_of_data_buffer )
  389. {
  390.    ASSERT_VALID( this );
  391.  
  392.    /*
  393.    ** data_buffer and size_of_data_buffer can be NULL
  394.    */
  395.  
  396.    DWORD temp_type_code = type_code;
  397.  
  398.    TCHAR temp_name[ 2048 ];
  399.  
  400.    ::ZeroMemory( temp_name, sizeof( temp_name ) );
  401.  
  402.    DWORD temp_name_size = sizeof( temp_name );
  403.    
  404.    m_ErrorCode = ::RegEnumValue( m_KeyHandle,
  405.                                  value_index,
  406.                                  temp_name,
  407.                                 &temp_name_size,
  408.                                  NULL,
  409.                                 &temp_type_code,
  410.                                  data_buffer,
  411.                                 &size_of_data_buffer );
  412.  
  413.    if ( m_ErrorCode == ERROR_SUCCESS )
  414.    {
  415.       type_code     = (KeyValueTypes) temp_type_code;
  416.       name_of_value = temp_name;
  417.  
  418.       return( TRUE );
  419.    }
  420.    else
  421.    {
  422.       return( FALSE );
  423.    }
  424. }
  425.  
  426. BOOL CRegistry::Flush( void )
  427. {
  428.    ASSERT_VALID( this );
  429.  
  430.    m_ErrorCode = ::RegFlushKey( m_KeyHandle );
  431.  
  432.    if ( m_ErrorCode == ERROR_SUCCESS )
  433.    {
  434.       return( TRUE );
  435.    }
  436.    else
  437.    {
  438.       return( FALSE );
  439.    }
  440. }
  441.  
  442. BOOL CRegistry::GetBinaryValue( LPCTSTR name_of_value, CByteArray& return_array )
  443. {
  444.    ASSERT_VALID( this );
  445.    ASSERT( name_of_value != NULL );
  446.  
  447.    if ( name_of_value == NULL )
  448.    {
  449.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  450.       return( FALSE );
  451.    }
  452.  
  453.    DWORD size_of_buffer = m_LongestValueDataLength;
  454.  
  455.    LPBYTE memory_buffer = (LPBYTE) new BYTE[ size_of_buffer ];
  456.  
  457.    if ( memory_buffer == NULL )
  458.    {
  459.       m_ErrorCode = ::GetLastError();
  460.       return( FALSE );
  461.    }
  462.  
  463.    BOOL return_value = TRUE;
  464.  
  465.    KeyValueTypes type = typeBinary;
  466.  
  467.    if ( QueryValue( name_of_value, type, memory_buffer, size_of_buffer ) == TRUE )
  468.    {
  469.       /*
  470.       ** We've got data so give it back to the caller
  471.       */
  472.  
  473.       return_array.RemoveAll();
  474.  
  475.       DWORD index = 0;
  476.  
  477.       while( index < size_of_buffer )
  478.       {
  479.          return_array.Add( memory_buffer[ index ] );
  480.          index++;
  481.       }
  482.  
  483.       return_value = TRUE;
  484.    }
  485.    else
  486.    {
  487.       return_value = FALSE;
  488.    }
  489.  
  490.    delete [] memory_buffer;
  491.  
  492.    return( return_value );
  493. }
  494.  
  495. void CRegistry::GetClassName( CString& class_name ) const
  496. {
  497.    class_name = m_ClassName;
  498. }
  499.  
  500. void CRegistry::GetComputerName( CString& computer_name ) const
  501. {
  502.    computer_name = m_ComputerName;
  503. }
  504.  
  505. BOOL CRegistry::GetDoubleWordValue( LPCTSTR name_of_value, DWORD& return_value )
  506. {
  507.    ASSERT_VALID( this );
  508.    ASSERT( name_of_value != NULL );
  509.  
  510.    if ( name_of_value == NULL )
  511.    {
  512.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  513.       return( FALSE );
  514.    }
  515.  
  516.    DWORD size_of_buffer = sizeof( DWORD );
  517.  
  518.    KeyValueTypes type = typeDoubleWord;
  519.  
  520.    return( QueryValue( name_of_value, type, (LPBYTE) &return_value, size_of_buffer ) );
  521. }
  522.  
  523. BOOL CRegistry::GetErrorCode( void ) const
  524. {
  525.    ASSERT_VALID( this );
  526.    return( m_ErrorCode );
  527. }
  528.  
  529. void CRegistry::GetKeyName( CString& key_name ) const
  530. {
  531.    key_name = m_KeyName;
  532. }
  533.  
  534. DWORD CRegistry::GetNumberOfSubkeys( void ) const
  535. {
  536.    return( m_NumberOfSubkeys );
  537. }
  538.  
  539. DWORD CRegistry::GetNumberOfValues( void ) const
  540. {
  541.    return( m_NumberOfValues );
  542. }
  543.  
  544. void CRegistry::GetRegistryName( CString& registry_name ) const
  545. {
  546.    registry_name = m_RegistryName;
  547. }
  548.  
  549. BOOL CRegistry::GetSecurity( const SECURITY_INFORMATION what_you_want_to_know,
  550.                              PSECURITY_DESCRIPTOR       data_buffer,
  551.                              DWORD&                     size_of_data_buffer )
  552. {
  553.    ASSERT_VALID( this );
  554.    ASSERT( data_buffer != NULL );
  555.  
  556.    if ( data_buffer == NULL )
  557.    {
  558.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  559.       return( FALSE );
  560.    }
  561.  
  562.    m_ErrorCode = ::RegGetKeySecurity( m_KeyHandle,
  563.                                       what_you_want_to_know,
  564.                                       data_buffer,
  565.                                      &size_of_data_buffer );
  566.  
  567.    if ( m_ErrorCode == ERROR_SUCCESS )
  568.    {
  569.       return( TRUE );
  570.    }
  571.    else
  572.    {
  573.       return( FALSE );
  574.    }
  575. }
  576.  
  577. BOOL CRegistry::GetStringValue( LPCTSTR name_of_value, CString& return_string )
  578. {
  579.    ASSERT_VALID( this );
  580.    ASSERT( name_of_value != NULL );
  581.  
  582.    if ( name_of_value == NULL )
  583.    {
  584.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  585.       return( FALSE );
  586.    }
  587.  
  588.    TCHAR temp_string[ 2048 ];
  589.    DWORD size_of_buffer = 2048;
  590.  
  591.    ::ZeroMemory( temp_string, sizeof( temp_string ) );
  592.  
  593.    KeyValueTypes type = typeString;
  594.  
  595.    if ( QueryValue( name_of_value, type, (LPBYTE) temp_string, size_of_buffer ) == TRUE )
  596.    {
  597.       return_string = temp_string;
  598.       return( TRUE );
  599.    }
  600.    else
  601.    {
  602.       return_string.Empty();
  603.       return( FALSE );
  604.    }
  605. }
  606.  
  607. BOOL CRegistry::GetStringArrayValue( LPCTSTR name_of_value, CStringArray& return_array )
  608. {
  609.    ASSERT_VALID( this );
  610.    ASSERT( name_of_value != NULL );
  611.  
  612.    if ( name_of_value == NULL )
  613.    {
  614.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  615.       return( FALSE );
  616.    }
  617.  
  618.    DWORD size_of_buffer = m_LongestValueDataLength;
  619.  
  620.    LPBYTE memory_buffer = (LPBYTE) new BYTE[ size_of_buffer ];
  621.  
  622.    if ( memory_buffer == NULL )
  623.    {
  624.       m_ErrorCode = ::GetLastError();
  625.       return( FALSE );
  626.    }
  627.  
  628.    BOOL return_value = TRUE;
  629.  
  630.    KeyValueTypes type = typeMultipleString; // A double NULL terminated string
  631.  
  632.    if ( QueryValue( name_of_value, type, memory_buffer, size_of_buffer ) == TRUE )
  633.    {
  634.       /*
  635.       ** We've got data so give it back to the caller
  636.       */
  637.  
  638.       LPTSTR strings = (LPTSTR) memory_buffer;
  639.  
  640.       return_array.RemoveAll();
  641.  
  642.       while( strings[ 0 ] != 0x00 )
  643.       {
  644.          return_array.Add( (LPCTSTR) strings );
  645.          strings += ( ::strlen( (LPCTSTR) strings ) + 1 );
  646.       }
  647.  
  648.       return_value = TRUE;
  649.    }
  650.    else
  651.    {
  652.       return_value = FALSE;
  653.    }
  654.  
  655.    delete [] memory_buffer;
  656.    
  657.    return( return_value );
  658. }
  659.  
  660. BOOL CRegistry::GetValue( LPCTSTR name_of_value, CByteArray& return_array )
  661. {
  662.    ASSERT_VALID( this );
  663.    ASSERT( name_of_value != NULL );
  664.  
  665.    if ( name_of_value == NULL )
  666.    {
  667.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  668.       return( FALSE );
  669.    }
  670.  
  671.    return( GetBinaryValue( name_of_value, return_array ) );
  672. }
  673.  
  674. BOOL CRegistry::GetValue( LPCTSTR name_of_value, DWORD& return_value )
  675. {
  676.    ASSERT_VALID( this );
  677.    ASSERT( name_of_value != NULL );
  678.  
  679.    if ( name_of_value == NULL )
  680.    {
  681.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  682.       return( FALSE );
  683.    }
  684.  
  685.    return( GetDoubleWordValue( name_of_value, return_value ) );
  686. }
  687.  
  688. BOOL CRegistry::GetValue( LPCTSTR name_of_value, CString& return_string )
  689. {
  690.    ASSERT_VALID( this );
  691.    ASSERT( name_of_value != NULL );
  692.  
  693.    if ( name_of_value == NULL )
  694.    {
  695.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  696.       return( FALSE );
  697.    }
  698.  
  699.    return( GetStringValue( name_of_value, return_string ) );
  700. }
  701.  
  702. BOOL CRegistry::GetValue( LPCTSTR name_of_value, CStringArray& return_array )
  703. {
  704.    ASSERT_VALID( this );
  705.    ASSERT( name_of_value != NULL );
  706.  
  707.    if ( name_of_value == NULL )
  708.    {
  709.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  710.       return( FALSE );
  711.    }
  712.  
  713.    return( GetStringArrayValue( name_of_value, return_array ) );
  714. }
  715.  
  716. BOOL CRegistry::Load( LPCTSTR name_of_subkey, LPCTSTR name_of_file_containing_information )
  717. {
  718.    ASSERT_VALID( this );
  719.    ASSERT( name_of_subkey != NULL );
  720.    ASSERT( name_of_file_containing_information != NULL );
  721.  
  722.    if ( name_of_subkey == NULL || name_of_file_containing_information == NULL )
  723.    {
  724.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  725.       return( FALSE );
  726.    }
  727.  
  728.    m_ErrorCode = ::RegLoadKey( m_RegistryHandle, name_of_subkey, name_of_file_containing_information );
  729.  
  730.    if ( m_ErrorCode == ERROR_SUCCESS )
  731.    {
  732.       return( TRUE );
  733.    }
  734.    else
  735.    {
  736.       return( FALSE );
  737.    }
  738. }
  739.  
  740. BOOL CRegistry::NotifyChange( const HANDLE             event_handle, 
  741.                               const NotifyChangeFilter changes_to_be_reported,
  742.                               const BOOL               this_subkey_or_all_subkeys,
  743.                               const BOOL               wait_for_change_or_signal_event )
  744. {
  745.    ASSERT_VALID( this );
  746.  
  747.    m_ErrorCode = ::RegNotifyChangeKeyValue( m_KeyHandle,
  748.                                             this_subkey_or_all_subkeys,
  749.                                             changes_to_be_reported,
  750.                                             event_handle,
  751.                                             wait_for_change_or_signal_event );
  752.  
  753.    if ( m_ErrorCode == ERROR_SUCCESS )
  754.    {
  755.       return( TRUE );
  756.    }
  757.    else
  758.    {
  759.       return( FALSE );
  760.    }
  761. }
  762.  
  763. BOOL CRegistry::Open( LPCTSTR name_of_subkey_to_open, const CreatePermissions security_access_mask )
  764. {
  765.    ASSERT_VALID( this );
  766.  
  767.    /*
  768.    ** name_of_subkey_to_open can be NULL
  769.    */
  770.  
  771.    m_ErrorCode = ::RegOpenKeyEx( m_RegistryHandle, name_of_subkey_to_open, NULL, security_access_mask, &m_KeyHandle );
  772.  
  773.    if ( m_ErrorCode == ERROR_SUCCESS )
  774.    {
  775.       QueryInfo();
  776.       m_KeyName = name_of_subkey_to_open;
  777.  
  778.       return( TRUE );
  779.    }
  780.    else
  781.    {
  782.       return( FALSE );
  783.    }
  784. }
  785.  
  786. BOOL CRegistry::QueryInfo( void )
  787. {
  788.    ASSERT_VALID( this );
  789.  
  790.    TCHAR class_name[ 2048 ];
  791.  
  792.    DWORD size_of_class_name = sizeof( class_name ) - 1;
  793.  
  794.    ::ZeroMemory( class_name, sizeof( class_name ) );
  795.  
  796.    m_ErrorCode = ::RegQueryInfoKey( m_KeyHandle,
  797.                                     class_name,
  798.                                    &size_of_class_name,
  799.                           (LPDWORD) NULL,
  800.                                    &m_NumberOfSubkeys,
  801.                                    &m_LongestSubkeyNameLength,
  802.                                    &m_LongestClassNameLength,
  803.                                    &m_NumberOfValues,
  804.                                    &m_LongestValueNameLength,
  805.                                    &m_LongestValueDataLength,
  806.                                    &m_SecurityDescriptorLength,
  807.                                    &m_LastWriteTime );
  808.  
  809.    if ( m_ErrorCode == ERROR_SUCCESS )
  810.    {
  811.       m_ClassName = class_name;
  812.  
  813.       return( TRUE );
  814.    }
  815.    else
  816.    {
  817.       return( FALSE );
  818.    }
  819. }
  820.  
  821. BOOL CRegistry::QueryValue( LPCTSTR        name_of_value, 
  822.                             KeyValueTypes& value_type, 
  823.                             LPBYTE         address_of_buffer, 
  824.                             DWORD&         size_of_buffer )
  825. {
  826.    ASSERT_VALID( this );
  827.    ASSERT( name_of_value != NULL );
  828.  
  829.    /*
  830.    ** address_of_buffer and size_of_buffer can be NULL
  831.    */
  832.  
  833.    if ( name_of_value == NULL )
  834.    {
  835.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  836.       return( FALSE );
  837.    }
  838.  
  839.    DWORD temp_data_type = (DWORD) value_type;
  840.  
  841.    m_ErrorCode = ::RegQueryValueEx( m_KeyHandle,
  842.                            (char *) name_of_value,
  843.                                     NULL,
  844.                                    &temp_data_type,
  845.                                     address_of_buffer,
  846.                                    &size_of_buffer );
  847.  
  848.    if ( m_ErrorCode == ERROR_SUCCESS )
  849.    {
  850.       value_type = (KeyValueTypes) temp_data_type;
  851.       return( TRUE );
  852.    }
  853.    else
  854.    {
  855.       return( FALSE );
  856.    }
  857. }
  858.  
  859. BOOL CRegistry::Replace( LPCTSTR name_of_subkey,
  860.                          LPCTSTR name_of_file_with_new_data,
  861.                          LPCTSTR name_of_backup_file )
  862. {
  863.    ASSERT_VALID( this );
  864.    ASSERT( name_of_subkey             != NULL );
  865.    ASSERT( name_of_file_with_new_data != NULL );
  866.    ASSERT( name_of_backup_file        != NULL );
  867.  
  868.    if ( name_of_subkey             == NULL ||
  869.         name_of_file_with_new_data == NULL ||
  870.         name_of_backup_file        == NULL )
  871.    {
  872.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  873.       return( FALSE );
  874.    }
  875.  
  876.    m_ErrorCode = ::RegReplaceKey( m_KeyHandle, 
  877.                                   name_of_subkey,
  878.                                   name_of_file_with_new_data,
  879.                                   name_of_backup_file );
  880.  
  881.    if ( m_ErrorCode == ERROR_SUCCESS )
  882.    {
  883.       return( TRUE );
  884.    }
  885.    else
  886.    {
  887.       return( FALSE );
  888.    }
  889. }
  890.  
  891. BOOL CRegistry::Restore( LPCTSTR name_of_file_holding_saved_tree, const DWORD volatility_flags )
  892. {
  893.    ASSERT_VALID( this );
  894.    ASSERT( name_of_file_holding_saved_tree != NULL );
  895.  
  896.    if ( name_of_file_holding_saved_tree == NULL )
  897.    {
  898.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  899.       return( FALSE );
  900.    }
  901.  
  902.    m_ErrorCode = ::RegRestoreKey( m_KeyHandle,
  903.                                   name_of_file_holding_saved_tree,
  904.                                   volatility_flags );
  905.  
  906.    if ( m_ErrorCode == ERROR_SUCCESS )
  907.    {
  908.       return( TRUE );
  909.    }
  910.    else
  911.    {
  912.       return( FALSE );
  913.    }
  914. }
  915.  
  916. BOOL CRegistry::Save( LPCTSTR name_of_file_to_hold_tree, LPSECURITY_ATTRIBUTES security_attributes_p )
  917. {
  918.    ASSERT_VALID( this );
  919.    ASSERT( name_of_file_to_hold_tree != NULL );
  920.  
  921.    if ( name_of_file_to_hold_tree == NULL )
  922.    {
  923.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  924.       return( FALSE );
  925.    }
  926.  
  927.    m_ErrorCode = ::RegSaveKey( m_KeyHandle, name_of_file_to_hold_tree, security_attributes_p );
  928.  
  929.    if ( m_ErrorCode == ERROR_SUCCESS )
  930.    {
  931.       return( TRUE );
  932.    }
  933.    else
  934.    {
  935.       return( FALSE );
  936.    }
  937. }
  938.  
  939. BOOL CRegistry::SetBinaryValue( LPCTSTR name_of_value, const CByteArray& bytes_to_write )
  940. {
  941.    ASSERT_VALID( this );
  942.    ASSERT( name_of_value != NULL );
  943.  
  944.    if ( name_of_value == NULL )
  945.    {
  946.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  947.       return( FALSE );
  948.    }
  949.  
  950.    DWORD size_of_buffer = bytes_to_write.GetSize();
  951.  
  952.    LPBYTE memory_buffer = new BYTE[ size_of_buffer ];
  953.  
  954.    if ( memory_buffer == NULL )
  955.    {
  956.       m_ErrorCode = ::GetLastError();
  957.       return( FALSE );
  958.    }
  959.  
  960.    DWORD index = 0;
  961.  
  962.    while( index < size_of_buffer )
  963.    {
  964.       memory_buffer[ index ] = bytes_to_write[ index ];
  965.       index++;
  966.    }
  967.  
  968.    BOOL return_value = SetValue( name_of_value, typeBinary, memory_buffer, size_of_buffer );
  969.  
  970.    delete [] memory_buffer;
  971.  
  972.    return( return_value );
  973. }
  974.  
  975. BOOL CRegistry::SetDoubleWordValue( LPCTSTR name_of_value, DWORD value_to_write )
  976. {
  977.    ASSERT_VALID( this );
  978.    ASSERT( name_of_value != NULL );
  979.  
  980.    if ( name_of_value == NULL )
  981.    {
  982.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  983.       return( FALSE );
  984.    }
  985.  
  986.    return( SetValue( name_of_value, typeDoubleWord, (const PBYTE) &value_to_write, sizeof( DWORD ) ) );
  987. }
  988.  
  989. BOOL CRegistry::SetSecurity( const SECURITY_INFORMATION& security_information,
  990.                              const PSECURITY_DESCRIPTOR  security_descriptor_p )
  991. {
  992.    ASSERT_VALID( this );
  993.    ASSERT( security_descriptor_p != NULL );
  994.  
  995.    if ( security_descriptor_p == NULL )
  996.    {
  997.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  998.       return( FALSE );
  999.    }
  1000.  
  1001.    m_ErrorCode = ::RegSetKeySecurity( m_KeyHandle, security_information, security_descriptor_p );
  1002.  
  1003.    if ( m_ErrorCode == ERROR_SUCCESS )
  1004.    {
  1005.       return( TRUE );
  1006.    }
  1007.    else
  1008.    {
  1009.       return( FALSE );
  1010.    }
  1011. }
  1012.  
  1013. BOOL CRegistry::SetStringValue( LPCTSTR name_of_value, const CString& string_value )
  1014. {
  1015.    ASSERT_VALID( this );
  1016.    ASSERT( name_of_value != NULL );
  1017.  
  1018.    if ( name_of_value == NULL )
  1019.    {
  1020.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  1021.       return( FALSE );
  1022.    }
  1023.  
  1024.    return( SetValue( name_of_value, typeString, (const PBYTE) (const char *) string_value, string_value.GetLength() + 1 ) );
  1025. }
  1026.  
  1027. BOOL CRegistry::SetStringArrayValue( LPCTSTR name_of_value, const CStringArray& string_array )
  1028. {
  1029.    ASSERT_VALID( this );
  1030.    ASSERT( name_of_value != NULL );
  1031.  
  1032.    if ( name_of_value == NULL )
  1033.    {
  1034.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  1035.       return( FALSE );
  1036.    }
  1037.  
  1038.    DWORD size_of_buffer = 0;
  1039.  
  1040.    /*
  1041.    ** Find out how big our buffer needs to be...
  1042.    */
  1043.  
  1044.    int index             = 0;
  1045.    int number_of_strings = string_array.GetSize();
  1046.  
  1047.    CString temp_string;
  1048.  
  1049.    while( index < number_of_strings )
  1050.    {
  1051.       temp_string = string_array[ index ];
  1052.       size_of_buffer += temp_string.GetLength() + 1;
  1053.       index++;
  1054.    }
  1055.  
  1056.    /*
  1057.    ** Don't forget the second NULL needed for double null terminated strings...
  1058.    */
  1059.  
  1060.    size_of_buffer++;
  1061.  
  1062.    LPBYTE memory_buffer = new BYTE[ size_of_buffer ];
  1063.  
  1064.    if ( memory_buffer == NULL )
  1065.    {
  1066.       m_ErrorCode = ::GetLastError();
  1067.       return( FALSE );
  1068.    }
  1069.  
  1070.    ::ZeroMemory( memory_buffer, size_of_buffer );
  1071.  
  1072.    /*
  1073.    ** OK, now add the strings to the memory buffer
  1074.    */
  1075.  
  1076.    LPTSTR string = (LPTSTR) memory_buffer;
  1077.  
  1078.    index             = 0;
  1079.    int string_length = 0;
  1080.  
  1081.    while( index < number_of_strings )
  1082.    {
  1083.       temp_string = string_array[ index ];
  1084.       ::strcpy( &string[ string_length ], temp_string );
  1085.       string_length += temp_string.GetLength() + 1;
  1086.  
  1087.       index++;
  1088.    }
  1089.  
  1090.    string_length++;
  1091.  
  1092.    BOOL return_value = TRUE;
  1093.  
  1094.    KeyValueTypes type = typeMultipleString; // A double NULL terminated string
  1095.  
  1096.    if ( SetValue( name_of_value, type, memory_buffer, size_of_buffer ) != TRUE )
  1097.    {
  1098.       return_value = FALSE;
  1099.    }
  1100.  
  1101.    delete [] memory_buffer;
  1102.  
  1103.    return( return_value );
  1104. }
  1105.  
  1106. BOOL CRegistry::SetValue( LPCTSTR name_of_value, const CByteArray& bytes_to_write )
  1107. {
  1108.    ASSERT_VALID( this );
  1109.    ASSERT( name_of_value != NULL );
  1110.  
  1111.    if ( name_of_value == NULL )
  1112.    {
  1113.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  1114.       return( FALSE );
  1115.    }
  1116.  
  1117.    return( SetBinaryValue( name_of_value, bytes_to_write ) );
  1118. }
  1119.  
  1120. BOOL CRegistry::SetValue( LPCTSTR name_of_value, DWORD value )
  1121. {
  1122.    ASSERT_VALID( this );
  1123.    ASSERT( name_of_value != NULL );
  1124.  
  1125.    if ( name_of_value == NULL )
  1126.    {
  1127.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  1128.       return( FALSE );
  1129.    }
  1130.  
  1131.    return( SetDoubleWordValue( name_of_value, value ) );
  1132. }
  1133.  
  1134. BOOL CRegistry::SetValue( LPCTSTR name_of_value, const CStringArray& strings_to_write )
  1135. {
  1136.    ASSERT_VALID( this );
  1137.    ASSERT( name_of_value != NULL );
  1138.  
  1139.    if ( name_of_value == NULL )
  1140.    {
  1141.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  1142.       return( FALSE );
  1143.    }
  1144.  
  1145.    return( SetStringArrayValue( name_of_value, strings_to_write ) );
  1146. }
  1147.  
  1148. BOOL CRegistry::SetValue( LPCTSTR name_of_value, const CString& string_to_write )
  1149. {
  1150.    ASSERT_VALID( this );
  1151.    ASSERT( name_of_value != NULL );
  1152.  
  1153.    if ( name_of_value == NULL )
  1154.    {
  1155.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  1156.       return( FALSE );
  1157.    }
  1158.  
  1159.    return( SetStringValue( name_of_value, string_to_write ) );
  1160. }
  1161.  
  1162. BOOL CRegistry::SetValue( LPCTSTR             name_of_value, 
  1163.                           const KeyValueTypes type_of_value_to_set, 
  1164.                           const PBYTE         address_of_value_data, 
  1165.                           const DWORD         size_of_data )
  1166. {
  1167.    ASSERT_VALID( this );
  1168.    ASSERT( name_of_value         != NULL );
  1169.    ASSERT( address_of_value_data != NULL );
  1170.  
  1171.    if ( name_of_value == NULL || address_of_value_data == NULL )
  1172.    {
  1173.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  1174.       return( FALSE );
  1175.    }
  1176.  
  1177.    m_ErrorCode = ::RegSetValueEx( m_KeyHandle,
  1178.                                   name_of_value,
  1179.                                   0,
  1180.                                   type_of_value_to_set,
  1181.                                   address_of_value_data,
  1182.                                   size_of_data );
  1183.  
  1184.    if ( m_ErrorCode == ERROR_SUCCESS )
  1185.    {
  1186.       return( TRUE );
  1187.    }
  1188.    else
  1189.    {
  1190.       return( FALSE );
  1191.    }
  1192. }
  1193.  
  1194. BOOL CRegistry::UnLoad( LPCTSTR name_of_subkey_to_unload )
  1195. {
  1196.    ASSERT_VALID( this );
  1197.    ASSERT( name_of_subkey_to_unload != NULL );
  1198.  
  1199.    if ( name_of_subkey_to_unload == NULL )
  1200.    {
  1201.       m_ErrorCode = ERROR_INVALID_PARAMETER;
  1202.       return( FALSE );
  1203.    }
  1204.  
  1205.    m_ErrorCode = ::RegUnLoadKey( m_KeyHandle, name_of_subkey_to_unload );
  1206.  
  1207.    if ( m_ErrorCode == ERROR_SUCCESS )
  1208.    {
  1209.       return( TRUE );
  1210.    }
  1211.    else
  1212.    {
  1213.       return( FALSE );
  1214.    }
  1215. }
  1216.